# -*- coding:utf-8 -*-
"""
=============================
this is a feibot product,
all rights reserved.
www.feibot.com
@author: Gu Tianyuan
@email: g@feibot.com
@time: ${DATE}:${TIME}
@product: ${PRODUCT_NAME}
=============================
"""
import datetime
import threading

from PyQt5.QtCore import *
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QDialog, QApplication

from gtyUI.uiFiles import ui_mainDialog, ui_mainAiDialog
from gtyUI import config, uiEventEngine, activeSetting, operate, askDialog
from gtyTools import tools, gtyLog, gitTools, systemTools
from gtyConfig import language, systemConfig, configFileHandler

import sys
import gtyTools.gtyTypes
import time
import traceback
import os

import gtySocket.socketTools


def detectDevice():
    try:
        with open("/proc/device-tree/model", "r") as f:
            info = f.read().lower()
        if 'jetson' in info:
            return ui_mainAiDialog.Ui_Form
        else:
            return ui_mainDialog.Ui_Form
    except FileNotFoundError:
        pass


BaseClass = detectDevice()


class MainGuiModel(QDialog, BaseClass):

    def __init__(self, eventQ, parent=None):
        super(MainGuiModel, self).__init__(parent)

        # ==========变量的定义===================
        # 配置的控制接口
        self.configHandlers = gtyTools.gtyTypes.ConfigHandlers()
        # 设备状态
        self.state = gtyTools.gtyTypes.machineState()
        # 通道状态
        self.channels = gtyTools.gtyTypes.Channels()
        # 芯片数据
        self.tagsGot = gtyTools.gtyTypes.tagDataSummary()
        # 硬件（stm32板子）时间，精确到ms
        self.hardwareTime = gtyTools.gtyTypes.hardwareTime()
        # linux系统的时间，用于辅助
        self.linuxTime = gtyTools.gtyTypes.linuxTime()

        # 事件处理队列
        self.eventQ = eventQ
        # 事件驱动引擎
        self.eventEngine = uiEventEngine.uiEventEngine(self.eventQ)
        # 辅助变量
        self.var = gtyTools.gtyTypes.auxiliaryVariables()
        self.socketBuilder = gtySocket.socketTools.SocketBuild()
        self.timerIntervalMs = 10
        self.timer = QTimer(self)

        # =========系统的运行====================
        # 建立ui, UI控件的调整和配置
        self.initGui()
        # 变量的初始化
        self.initFields()
        # 更新显示
        self.initStateDisplay()
        # 启动事件驱动引擎
        self.initEventEngine()

        self.times = 0

        self.dialog = askDialog.AskDialog(self)

        # 客户自定义格式
        self.formatNum = self.configHandlers.machine.read("formatepc", "formatnum", "string", None)
        self.ShowfilteredtagsEnable = self.configHandlers.machine.read("reader", "ShowFilteredTags", "int", 0)

    '''
    ===============================================================================================================
    二、 工具函数
    ===============================================================================================================
    '''

    # GUI控件建立
    def initGui(self):
        self.setGeometry(0, 0, 800, 480)
        self.setWindowFlag(Qt.FramelessWindowHint)
        self.setupUi(self)
        self.update()
        # 用不同的语言初始化
        self.initInLanguage()
        self.initGuiConnections()
        # 0.05秒的定时器

        self.timer.timeout.connect(self.updateHardwareTimePer10ms)
        self.timer.start(self.timerIntervalMs)

        # 设置字体大小
        font = QFont()
        if language.language == 'english':
            font.setPointSize(18)
        else:
            font.setPointSize(20)
        self.gunButton.setFont(font)
        self.gunStopButton.setFont(font)
        self.configButton.setFont(font)
        self.resetDataButton.setFont(font)
        self.changeDisplayButton.setFont(font)
        if language.language == 'english':
            font.setPointSize(16)
            self.changeDisplayButton.setFont(font)

    # 初始化变量
    def initFields(self):
        # ==========变量的定义===================
        # 设备状态
        self.state.machineId = tools.getMachineId(self.configHandlers.mmc.read("machine", "machineId"))
        self.getFieldsFromConfigFiles()
        self.channels.setBtns([self.CH1_Button, self.CH2_Button, self.CH3_Button, self.CH4_Button,
                               self.CH5_Button, self.CH6_Button, self.CH7_Button, self.CH8_Button,
                               self.PRO1_Button, self.PRO2_Button, self.PRO3_Button, self.PRO4_Button,
                               self.PRO5_Button, self.PRO6_Button, self.PRO7_Button, self.PRO8_Button,
                               self.Active_Button])

        # 初始状态为发布模式
        self.configHandlers.state.write('machine', 'releaseMode', 'release')
        # 限制调试模式使用
        self.sendEvent('UART', 'uart_sendReleaseMode', ['release'])
        # 使能或禁用蜂鸣器
        self.toggleBeep()
        with open('./Newevent.ini', 'r') as f:
            self.newEventId = f.readline().strip()

        self.updateValuesFromEventConfigFile()
        commitId, branchName = gitTools.getGitHeadInfo()
        if branchName == 'dev':
            self.machineConfig = configFileHandler.UserConfigHandler()
            self.machineConfig.write("reader", "allowEpcByteLength", "2,4,6,8,12,16")
        self.var.enableSocketToServer = self.configHandlers.machine.read('socketToServer', 'enable', 'int', 0)
        self.var.hardwareType = self.configHandlers.machine.read('machine', 'hardwareType', 'string', 'F2000').upper()
        if self.var.hardwareType != 'A400':
            for i in range(1, 5):
                self.sendEvent('UART', 'uart_getReaderPower', i + 2)  # 读取读卡功率
                time.sleep(0.1)
        stateString = 'L1:---' + " L2:---" + ' power:---' + ' ch:---'
        self.label_34.setText(stateString)
        self.channels.hide(True, 'all')
        self.Passive_Button.hide()
        self.passiveRBtn.hide()
        self.activeRBtn.hide()

        # 对于定制的软件，不显示feibot品牌的提示信息和窗口左上角的logo
        userDefinedPicUrl = self.configHandlers.machine.read("machine", "aboutImage", "string", "")
        if userDefinedPicUrl != "":
            self.textBrowser.setText("")
            systemConfig.param.windowLogoPath = ""

        # 根据配置状态调整页面布局
        if self.var.hardwareType == 'F800' or self.var.hardwareType == 'T400':
            self.channels.hide(True, 'pro')
            self.channels.hide(True, 'active')
            self.channels.hide(False, 'innerChannels')
            self.Passive_Button.hide()
            self.passiveRBtn.hide()
            self.activeRBtn.hide()
            if self.var.hardwareType == 'F800':
                self.textBrowser.setMaximumWidth(250)
            self.label_34.hide()
            self.label_29.hide()
            self.stopReadingButton.hide()
            self.startReadingButton.hide()
            # self.changeDisplayButton.setStyleSheet(systemConfig.param.btnDisabledStyle)
        if self.var.hardwareType == "A400":
            self.label_7.hide()
            self.label_8.hide()
            self.label_27.hide()
            self.label_28.hide()
            self.channels.hide(True, 'pro')
            self.channels.hide(True, 'innerChannels')
            self.Passive_Button.hide()
            self.passiveRBtn.hide()
            self.activeRBtn.hide()
            self.startReadingButton.hide()
            self.stopReadingButton.hide()
        if self.var.hardwareType == 'F2000':
            self.startReadingButton.hide()
            self.stopReadingButton.hide()

    # 刷新状态显示
    def initStateDisplay(self):
        self.labelEventName.setText(self.configHandlers.event.read("event", "eventName"))
        if self.newEventId == '':
            self.label_19.setText(self.state.eventId)
        else:
            # self.label_19.setText(f"{self.state.eventId}->{self.Reeventid}")
            self.label_19.setText(f"{self.newEventId}")
        s = self.configHandlers.event.read(self.state.machineId, "machinePosition") \
            + "|" + self.configHandlers.event.read(self.state.machineId, "timingPoint")
        self.label_20.setText(s)
        self.label_24.setText(self.state.machineId)
        # 显示ip地址
        ips = tools.getIpAddr()
        if ips is not []:
            ipStr = ''
            for ip in ips:
                ipStr += ip + ','
            ipStr = ipStr[:-1]
            self.textBrowser.append('ip: ' + ipStr + ' ')
        # 显示Git版本状态信息
        commitId, branchName = gitTools.getGitHeadInfo()
        gitInfoText = ''
        if branchName != '':
            self.var.gitBranch = branchName
            if 'dev' in branchName:
                # 防止国外客户混淆
                pass
                # warningInfo = '=====!!!!!!!!!!===='
                # warningInfo += '\n' + language.mainPage_devWarning
                # warningInfo += '\n====!!!!!!!!!!====='
                # self.textBrowser.append(warningInfo)
            gitInfoText += branchName
        if commitId != '':
            self.var.gitCommitId = commitId
            if gitInfoText != '':
                gitInfoText += ' / ' + commitId
            else:
                gitInfoText += commitId
        self.labelGitVersion.setText(gitInfoText)

    # 初始化eventEngine
    def initEventEngine(self):
        # 事件处理引擎处理
        try:
            self.eventEngine.eventList['everySecond'].connect(self.taskPerSecond)  # 完成每秒一次的操作
            self.eventEngine.eventList['every100ms'].connect(self.taskPer100ms)
            self.eventEngine.eventList["ui_getEPC"].connect(self.getEpc)
            self.eventEngine.eventList["ui_log"].connect(self.outputLog)
            self.eventEngine.eventList["ui_batteryVoltage"].connect(self.updateBatteryPercentage)
            self.eventEngine.eventList["ui_loadEventConfigFile"].connect(self.updateValuesFromEventConfigFile)
            self.eventEngine.eventList["ui_updateMainDialogEventInfo"].connect(self.updateValuesFromEventConfigFile)
            self.eventEngine.eventList["ui_getFirmwareVersion"].connect(self.updateFirmwareVersion)
            self.eventEngine.eventList["ui_startOrStropReading"].connect(self.readControlByReader)
            self.eventEngine.eventList["ui_powerControl"].connect(self.powerManage)
            self.eventEngine.eventList["ui_Ds3231TimeTick"].connect(self.showTimePer1Second)
            self.eventEngine.eventList["ui_Ds3231Date"].connect(self.updateDs3231Date)
            self.eventEngine.eventList["ui_internetConnectionReport"].connect(self.updateInternetConnectionState)
            self.eventEngine.eventList["ui_uploadResultFileToServer"].connect(self.handleFileUploadResult)  # 更新上传是否成功
            self.eventEngine.eventList["ui_gunStartButtonPressedShort"].connect(self.gunStart)  # 枪响按钮被按下
            self.eventEngine.eventList["ui_gunStartButtonPressedLong"].connect(self.gunStop)  # 枪响复位按钮按下
            self.eventEngine.eventList["ui_chSettingResponse"].connect(self.chEnableResponse)  # 设置通道状态后的回复
            self.eventEngine.eventList["ui_testTagReadTimes"].connect(self.updateTestTagShow)  # 显示测试卡读到的次数
            self.eventEngine.eventList["ui_stm32Cmd"].connect(self.stm32Cmd)  # 用来处理stm32发来的指令
            self.eventEngine.eventList["ui_updateMainDialogValue"].connect(
                self.updateValuesFromEventConfigFile)  # 更新主页面里的值
            self.eventEngine.eventList["ui_uploadTagNumInWait"].connect(self.updateCpValueNumLeft)  # 剩余的待上传的cp数据
            self.eventEngine.eventList["ui_warning"].connect(self.showWarning)
            self.eventEngine.eventList["ui_updateFieldsFromConfigFile"].connect(self.getFieldsFromConfigFiles)
            self.eventEngine.eventList["ui_socketGetGunTime"].connect(self.socketGetGunTime)
            self.eventEngine.eventList["ui_socketSendPackDataResult"].connect(self.socketSendPackDataResult)
            self.eventEngine.eventList["ui_getGitNewVersion"].connect(self.getGitNewVersion)
            self.eventEngine.eventList["ui_cpuRamInfo"].connect(self.updateCpuRamInfo)
            self.eventEngine.eventList["ui_getReaderPower"].connect(self.getReaderPower)
            self.eventEngine.eventList['ui_setDateTimeFromWeb'].connect(self.setDateTimeFromWeb)
            # 有源系统
            self.eventEngine.eventList['ui_getActiveHeartBeat'].connect(self.getActiveHeartBeat)
            self.eventEngine.eventList['ui_setPassOrAct'].connect(self.setPassiveOrActiveSlog)
            self.eventEngine.eventList['ui_setGateTime'].connect(self.setGateTime)
            self.eventEngine.eventList['ui_showShutdown'].connect(self.showShutdown)
            self.eventEngine.eventList['ui_showNotAllowedEpc'].connect(self.showNotAllowEpc)
            self.eventEngine.eventList['ui_socketGetReaderPower'].connect(self.socketGetReaderPower)
            self.eventEngine.eventList['ui_updateReaderPower'].connect(self.updateReaderPower)
            self.eventEngine.eventList['ui_socketGetReaderChannel'].connect(self.socketGetReaderChannel)
            self.eventEngine.eventList['ui_getReaderStatusFromStm32'].connect(self.updateReaderStatus)
            self.eventEngine.start()
        except Exception as e:
            traceback.print_exc()
            print(e)

    '''
    ===============================================================================================================
    二、 工具函数
    ===============================================================================================================
    '''

    # 从配置文件更新不影响页面显示的变量
    def getFieldsFromConfigFiles(self):
        self.configHandlers = gtyTools.gtyTypes.ConfigHandlers()
        self.state.gateTime = self.configHandlers.machine.read("machine", "gateTime", "float", 1)
        self.state.allowEpcByteNumList = self.configHandlers.machine.read("reader", "allowEpcByteLength").split(",")
        self.state.truncateEpcByteNum = self.configHandlers.machine.read("reader", "truncateEpcByteNum", "int", 0)

    # 建立GUI的信号槽连接
    def initGuiConnections(self):
        self.changeDisplayButton.clicked.connect(self.toggleChLog)
        self.configButton.clicked.connect(self.config)
        self.gunButton.clicked.connect(self.gunStart)
        self.gunStopButton.clicked.connect(self.gunStop)
        self.resetDataButton.clicked.connect(self.resetData)
        self.CH1_Button.clicked.connect(lambda: self.chBtnClicked(1))
        self.CH2_Button.clicked.connect(lambda: self.chBtnClicked(2))
        self.CH3_Button.clicked.connect(lambda: self.chBtnClicked(3))
        self.CH4_Button.clicked.connect(lambda: self.chBtnClicked(4))
        self.CH5_Button.clicked.connect(lambda: self.chBtnClicked(5))
        self.CH6_Button.clicked.connect(lambda: self.chBtnClicked(6))
        self.CH7_Button.clicked.connect(lambda: self.chBtnClicked(7))
        self.CH8_Button.clicked.connect(lambda: self.chBtnClicked(8))
        self.PRO1_Button.clicked.connect(lambda: self.chBtnClicked(9))
        self.PRO2_Button.clicked.connect(lambda: self.chBtnClicked(10))
        self.PRO3_Button.clicked.connect(lambda: self.chBtnClicked(11))
        self.PRO4_Button.clicked.connect(lambda: self.chBtnClicked(12))
        self.PRO5_Button.clicked.connect(lambda: self.chBtnClicked(13))
        self.PRO6_Button.clicked.connect(lambda: self.chBtnClicked(14))
        self.PRO7_Button.clicked.connect(lambda: self.chBtnClicked(15))
        self.PRO8_Button.clicked.connect(lambda: self.chBtnClicked(16))
        self.Active_Button.clicked.connect(self.activeSetting)
        self.Passive_Button.clicked.connect(self.operate)
        self.passiveRBtn.clicked.connect(self.setPassive)
        self.activeRBtn.clicked.connect(self.setActive)
        self.startReadingButton.clicked.connect(self.startReading)
        self.stopReadingButton.clicked.connect(self.stopReading)


    # 根据语言初始化文字
    def initInLanguage(self):
        self.label_3.setText(language.mainPage_label3)
        self.label_17.setText(language.mainPage_label17)
        self.label_31.setText(language.mainPage_label31)
        self.label.setText(language.mainPage_label)
        self.label_5.setText(language.mainPage_label5)
        self.label_15.setText(language.mainPage_label15)
        self.label_7.setText(language.mainPage_label7)
        self.label_23.setText(language.mainPage_label23)
        self.label_9.setText(language.mainPage_label9)
        self.label_11.setText(language.mainPage_label11)
        self.label_13.setText(language.mainPage_label13)
        self.label_27.setText(language.mainPage_label27)
        self.label_21.setText(language.mainPage_label21)
        self.gunButton.setText(language.mainPage_gunButton)
        self.gunStopButton.setText(language.mainPage_gunStopButton)
        self.configButton.setText(language.mainPage_configButton)
        self.resetDataButton.setText(language.mainPage_resetDataButton)
        self.label_28.setText(language.mainPage_stopReading)
        self.label_8.setText(language.mainPage_stopReading)
        self.label_29.setText(language.mainPage_activeChannel)
        self.label_34.setText(language.mainPage_activeNoActivating)
        self.changeDisplayButton.setText(language.mainPage_displayChannels)
        self.Active_Button.setText(language.mainPage_active)
        self.Passive_Button.setText(language.mainPage_passive)
        self.activeRBtn.setText(language.mainPage_active)
        self.passiveRBtn.setText(language.mainPage_passive)
        self.startReadingButton.setText(language.mainPage_startReading)
        self.stopReadingButton.setText(language.mainPage_stopReadingBtn)

    # 发生事件
    def sendEvent(self, task, eventName, eventData=None):
        if eventData is None:
            eventData = []
        e = [eventName, eventData]
        try:
            if task.upper() in self.eventQ.keys():
                self.eventQ[task.upper()].put(e)
        except Exception as e:
            print(e)

    # 日志输出
    def log(self, text):
        self.sendEvent('UI', 'ui_log', eventData=text)

    # 每0.1秒完成的任务
    def taskPer100ms(self):
        # 比赛历时
        self.showProcessedTime()
        # 刷新epc的页面显示

        self.times += 1
        if self.times % 2 == 0:
            self.sendEvent('IO', 'io_sendHeartBeatToStm32', [])
        if self.var.epcDisplayBufText != '' and self.times % 2 == 0:
            self.label_12.setText((str(self.tagsGot.differentCheckedNum)))
            self.label_10.setText(str(self.tagsGot.totalCheckedNum))
            self.outputLog(self.var.epcDisplayBufText, self.var.epcDisplayBufTextLineNum)
            self.var.epcDisplayBufText = ''
            self.var.epcDisplayBufTextLineNum = 0

            if self.var.hardwareType != 'A400':
                if self.linuxTime.secondCounter > self.channels.testNumDisplayTilSecond:
                    for ch in range(0, 16):
                        # 防止在读取的过程中关闭的通道会文本和0交替出现
                        if "CH" in self.channels.allChs[ch].chBtn.text() or "Pro" in self.channels.allChs[
                            ch].chBtn.text():
                            continue
                        self.channels.allChs[ch].chBtn.setText(str(self.channels.allChs[ch].tagReadNum))
        self.update_start_stop_reading_btn()


    # 完成每秒一次的任务，这里由linux系统时间控制
    def taskPerSecond(self):
        # 向stm32进程发送心跳包
        # self.sendEvent('IO', 'io_sendHeartBeatToStm32', [])
        self.linuxTime.secondCounter += 1

        # 刷新通知栏显示
        self.updateNoticeLabel()

        if len(self.tagsGot.checkedTagDict) >= 100000:
            self.tagsGot.checkedTagDict = {}

        if self.state.updateNotice != '' and self.linuxTime.secondCounter % 10 == 3:
            if self.state.updateNotice == 'software':
                self.outputLog(language.mainPage_newSoftware)
            elif self.state.updateNotice == 'firmware':
                self.outputLog(language.mainPage_newFirmware)

        # 通过IO进程检测网络连接状态
        if self.linuxTime.secondCounter % 5 == 1:
            self.checkServerConnection()

        if self.linuxTime.secondCounter == 2:
            self.sendEvent('UART', 'uart_askFirmwareVersion')
            self.sendEvent('UART', 'uart_channelOpen', [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])  # 默认开启全部端口



        if self.linuxTime.secondCounter == 5:
            if self.var.hardwareType == 'F2000':
                self.setPassvieOrActive()  # 开机5秒设置有源无源

        # 每10秒记录一下队列元素个数
        if self.linuxTime.secondCounter % 10 == 1:
            try:
                qSizeStr = ''
                for qName in self.eventQ.keys():
                    qSizeStr += str(self.eventQ[qName].qsize())
                gtyLog.log.write(__file__, "queue size", qSizeStr)
            except Exception as e:
                print(e)
        if self.linuxTime.secondCounter % 2 == 1:
            s = threading.Thread(target=self.getRunInfo)
            s.start()

        #####
        # socket 处理
        ####
        # 每1秒发送socket心跳包
        self.socketSendHeartBeat()
        # 每1秒发送日期和时间
        self.socketSendDate()
        self.socketSendTime()

        # 刷新页面启动时间显示
        self.labelStatus_2.setText(systemTools.getUptime(self.linuxTime.secondCounter))

        # 开机后的第4秒未在读取状态，则自动查询功率，如果功率查询不到，则设置为4号读卡器，并重启读卡器。上午七点前或下午3点后启动这个功能
        if 'reading' not in (
        self.state.readerState1, self.state.readerState2, self.state.readerState3, self.state.readerState4):
            if self.var.hardwareType in ["F800", "F2000"] \
                    and (self.hardwareTime.hour < 7 or self.hardwareTime.hour > 15):
                if self.linuxTime.secondCounter == 10 - 6:
                    self.sendEvent('UART', 'uart_getReaderPower', 3)  # 读取1号读卡器功率
                if self.linuxTime.secondCounter == 11 - 6:
                    self.sendEvent('UART', 'uart_getReaderPower', 4)  # 读取2号读卡器功率
                if self.linuxTime.secondCounter == 12 - 6:
                    if self.var.reader1Power == 0:
                        self.sendEvent('UART', 'uart_readerTypeAndVersion', [1, 3, 4, 0])
                        self.sendEvent('UART', 'uart_reBootReader', [1])
                        print(__file__, "set reader 1 type 4")
                if self.linuxTime.secondCounter == 13 - 6:
                    if self.var.reader2Power == 0:
                        self.sendEvent('UART', 'uart_readerTypeAndVersion', [1, 4, 4, 0])
                        self.sendEvent('UART', 'uart_reBootReader', [2])
                        print(__file__, "set reader 2 type 4")
                if self.linuxTime.secondCounter == 14 - 6:
                    self.sendEvent('UART', 'uart_getReaderPower', 5)  # 读取3号读卡器功率
                if self.linuxTime.secondCounter == 15 - 6:
                    self.sendEvent('UART', 'uart_getReaderPower', 6)  # 读取4号读卡器功率
                if self.linuxTime.secondCounter == 16 - 6:
                    if self.var.reader3Power == 0:
                        self.sendEvent('UART', 'uart_readerTypeAndVersion', [1, 5, 4, 0])
                        self.sendEvent('UART', 'uart_reBootReader', [3])
                        print(__file__, "set reader 3 type 4")
                if self.linuxTime.secondCounter == 17 - 6:
                    if self.var.reader4Power == 0:
                        self.sendEvent('UART', 'uart_readerTypeAndVersion', [1, 6, 4, 0])
                        self.sendEvent('UART', 'uart_reBootReader', [4])
                        print(__file__, "set reader 4 type 4")

    '''
    =============================================================================================================
    三、 事件处理函数，包括直接产生的事件和基于信号-槽的函数
    =============================================================================================================
    '''

    def updateValuesFromEventConfigFile(self):
        self.configHandlers = gtyTools.gtyTypes.ConfigHandlers()
        self.state.eventId = self.configHandlers.event.read("event", "eventId")
        if self.newEventId == '':
            self.label_19.setText(self.state.eventId)
        else:
            self.label_19.setText(f"{self.newEventId}")  # 重新自定义的ID
        self.labelEventName.setText(self.configHandlers.event.read("event", "eventName"))
        s = self.configHandlers.event.read(self.state.machineId, "machinePosition") \
            + "|" + self.configHandlers.event.read(self.state.machineId, "timingPoint")
        self.label_20.setText(s)
        # 输出调试模式标志
        if self.configHandlers.state.read('machine', 'releaseMode') == 'release':
            self.state.noticeLabelDict['releaseMode'] = language.mainPage_releaseMode
        else:
            self.state.noticeLabelDict['releaseMode'] = language.mainPage_TestMode
        self.updateNoticeLabel()

    # 刷新电池电量
    def updateBatteryPercentage(self, data):
        self.state.batteryPercentage = int(tools.batteryPercentage(data[0], self.var.hardwareType))
        self.label_22.setText(str(self.state.batteryPercentage) + '%')

    # 输出log
    def outputLog(self, text, lineNum=1, color=None):
        if self.state.textBrowserLineNum >= 3000:
            self.textBrowser.setText('')
            self.state.textBrowserLineNum = 0
        self.state.textBrowserLineNum += lineNum
        # 使用 HTML 格式设置颜色
        if color is not None:
            colored_text = f'<span style="color:{color}">{text}</span>'
            self.textBrowser.append(colored_text)
        else:
            self.textBrowser.append(text)

    # 显示当前时刻
    def showTimePer1Second(self, timeList):
        hour = timeList[0]
        minute = timeList[1]
        second = timeList[2]
        if second % 2 == 0:
            dt = '%02d:%02d:%02d' % (hour, minute, second)
        else:
            dt = '%02d %02d %02d' % (hour, minute, second)
        self.label_2.setText(dt)
        # 百分之一秒时间清零
        self.hardwareTime.hour = hour
        self.hardwareTime.minute = minute
        self.hardwareTime.second = second
        self.hardwareTime.ms = 0

    # 更新0.01秒
    def updateHardwareTimePer10ms(self):
        if self.hardwareTime.ms + self.timerIntervalMs < 1000:
            self.hardwareTime.ms += self.timerIntervalMs

    # 显示比赛已进行时间，采用的是linux系统自身的时间
    def showProcessedTime(self):
        if self.state.gunStartTime is not None:

            self.var.gunShowColon += 1
            if self.var.gunShowColon >= 20:
                self.var.gunShowColon = 0

            now = tools.getTimeStamp(self.hardwareTime.year, self.hardwareTime.month, self.hardwareTime.day,
                                     self.hardwareTime.hour, self.hardwareTime.minute, self.hardwareTime.second, 0)
            m, s = divmod(int(now - self.state.gunStartTimeString), 60)
            h, m = divmod(m, 60)
            if self.var.gunShowColon <= 10:
                text = ("%02d:%02d:%02d" % (h, m, s))
            else:
                text = ("%02d %02d %02d" % (h, m, s))
            self.label_6.setText(text)

    # 枪响
    def gunStart(self):
        self.state.gunStartTime = gtyTools.gtyTypes.timeInMs(
            self.hardwareTime.year, self.hardwareTime.month, self.hardwareTime.day,
            self.hardwareTime.hour, self.hardwareTime.minute, self.hardwareTime.second,
            self.hardwareTime.ms)
        self.state.gunStartTimeString = tools.getTimeStamp(self.state.gunStartTime.year, self.state.gunStartTime.month,
                                                           self.state.gunStartTime.day,
                                                           self.state.gunStartTime.hour, self.state.gunStartTime.minute,
                                                           self.state.gunStartTime.second, 0)
        self.label_16.setText("%02d:%02d:%02d.%02d" % (self.state.gunStartTime.hour, self.state.gunStartTime.minute,
                                                       self.state.gunStartTime.second, self.state.gunStartTime.ms / 10))
        font = QFont()
        font.setPointSize(13)
        self.label_16.setFont(font)
        self.socketGetGunTime()
        self.sendEvent('UART', "uart_beep", 0.5)
        if self.formatNum in ['foramt2', 'format8']:
            self.sendEvent('IO', "io_recoradGunTime", self.state.gunStartTime)
        print('================== GUN START =================')

    # 枪停止
    def gunStop(self):
        self.state.gunStartTime = None
        self.state.gunStartTimeString = None
        self.label_6.setText('------')
        self.label_16.setText('------')
        self.sendEvent('UART', "uart_beep", 0.5)
        print('================== GUN STOP =================')

    # 分读写器读取控制
    def readControlByReader(self, data):
        reader = data[0]
        cmd = data[1]
        cmdBranch = ''
        # 对于A400设备
        if self.var.hardwareType in ["A400"]:
            if cmd in ['onFromWeb', 'on']:
                self.sendEvent("UART", 'uart_active_lfControl', [int(reader), 1])
            elif cmd in ['off', 'offFromWeb']:
                self.sendEvent("UART", 'uart_active_lfControl', [int(reader), 0])
            return
        # 对于F800 F2000设备
        if self.var.hardwareType in ["F800", "F2000"]:
            self.machineState = self.configHandlers.machine.read('machine', 'machineState', 'string', 'Passive')
            if self.machineState == 'Passive':
                readerState = getattr(self.state, f'readerState{reader}')
                if (readerState == 'stopped' and cmd == 'x') or (cmd == 'on') or (
                        readerState == 'stopped' and cmd == 'onFromWeb'):
                    print(__file__, 'reader' + reader + ' start')
                    # 发送读取指令
                    if reader == '1':
                        self.label_8.setText(language.mainPage_reading)
                        self.state.readerState1 = 'reading'
                    if reader == '2':
                        self.label_28.setText(language.mainPage_reading)
                        self.state.readerState2 = 'reading'
                    if reader == '3':
                        self.state.readerState3 = 'reading'
                    if reader == '4':
                        self.state.readerState4 = 'reading'
                    for j in range(0, 2):
                        self.sendEvent('UART', 'uart_readControlCh' + reader, 1)  # 1表示开始读卡
                    self.sendEvent('UI', 'ui_updateOperateDialogReadingLabel', 'stop' + reader)
                    cmdBranch = 'start'
                if (readerState == 'reading' and cmd == 'x') or (cmd == 'off') or (
                        readerState == 'reading' and cmd == 'offFromWeb'):
                    print(__file__, 'reader' + reader + ' stop')
                    # 发送停止读取指令
                    if reader == '1':
                        self.label_8.setText(language.mainPage_stopReading)
                        self.state.readerState1 = 'stopped'
                    if reader == '2':
                        self.label_28.setText(language.mainPage_stopReading)
                        self.state.readerState2 = 'stopped'
                    if reader == '3':
                        self.state.readerState3 = 'stopped'
                    if reader == '4':
                        self.state.readerState4 = 'stopped'
                    for j in range(0, 5):
                        self.sendEvent('UART', 'uart_readControlCh' + reader, 0)  # 0表示停止读卡
                    self.sendEvent('UI', 'ui_updateOperateDialogReadingLabel', 'start' + reader)
                    cmdBranch = 'stop'
                # 操作成功的提示
                if cmdBranch in ['start', 'stop']:
                    self.sendEvent('UART', 'uart_beepHalfSecond')
                    text = language.mainPage_reader + reader + ': ' + cmdBranch
                    self.log(text)
            elif self.machineState == 'Active':
                if cmd in ['onFromWeb', 'on']:
                    self.sendEvent("UART", 'uart_active_lfControl', [int(reader), 1])
                elif cmd in ['off', 'offFromWeb']:
                    self.sendEvent("UART", 'uart_active_lfControl', [int(reader), 0])

    # 打开配置页面
    def config(self):
        configDialog = config.Config(self, self.eventQ)
        configDialog.exec_()

    # 重置统计量
    def resetData(self):
        try:
            self.tagsGot.reset()
            self.state.textBrowserLineNum = 0
            self.textBrowser.setText('')
            self.label_12.setText(str(0))
            self.label_10.setText(str(0))
            self.channels.resetNum()
            self.var.rawEpcNum = 0
            for ch in range(0, 8):
                if self.channels.allChs[ch].open == 1:
                    self.channels.allChs[ch].chBtn.setText('0')
            print('reset data display')
            if self.configHandlers.state.read('machine', 'releaseMode') != 'release':
                self.sendEvent('IO', 'io_resetData')
        except Exception as e:
            print(e)

    # 电源管理
    def powerManage(self, mode):
        print(__file__, mode)
        if mode == 'reboot':
            self.sendEvent('UART', 'uart_reboot', [])
            time.sleep(1)
            gtyLog.log.write(__file__, 'sudo reboot')
            gtyTools.tools.linuxSudoCmd('reboot')
            gtyTools.tools.linuxSudoCmd('kill all python3')
        elif mode == 'powerOff':
            self.sendEvent('UART', 'uart_shutDown', [])
            gtyLog.log.write(__file__, 'halt')
            gtyTools.tools.linuxSudoCmd('halt')
            gtyTools.tools.linuxSudoCmd('kill all python3')

    # 获得了EPC码的处理
    # 这里的l数据结构是：[timeList, epcList, ch,antenna,packId]
    def getEpc(self, data):
        for d in data:
            newTag = d[0]
            self.var.rawEpcNum += 1
            # 按客户定制的格式重新格式化EPC，如果处理后为空，则舍弃该数据
            if self.formatNum:
                Temp = tools.epcReformat(newTag, self.formatNum, self.ShowfilteredtagsEnable,
                                         self.sendEvent)  # 直接赋值给epcString会导致sendEvent无法发送正确的epcString
                if Temp == '':
                    return
                else:
                    newTag.epcString = Temp
            # 截取末尾长度（如果有设置）
            if self.state.truncateEpcByteNum > 0:
                if self.state.truncateEpcByteNum <= newTag.epcByteNum:
                    newTag.epcByteList = newTag.epcByteList[-self.state.truncateEpcByteNum:]
                    newTag.buildEpcString()
                    newTag.epcByteNum = self.state.truncateEpcByteNum
                else:
                    gtyLog.log.write(__file__,
                                     'getEpc: epcByteNum is less than truncateEpcByteNum :' + newTag.epcString)
                    if self.ShowfilteredtagsEnable:
                        self.showNotAllowEpc(newTag)
                    return
            # 过滤允许的开头字符，以逗号分隔
            try:
                allowStartStr_lst = self.configHandlers.machine.read('reader', 'allowEpcStartWith').split(',')
                if len(allowStartStr_lst) > 0 and allowStartStr_lst[0] != "":  # 如果没有配置 'allowEpcStartWith'，允许所有标签通过
                    allowEpcStart = False  # 用来标记是否允许通过
                    for allowStartStr in allowStartStr_lst:
                        if newTag.epcString.startswith(allowStartStr):
                            allowEpcStart = True  # 如果满足条件，标记为允许
                            break  # 找到一个匹配的开头后，退出循环
                    if not allowEpcStart:
                        gtyLog.log.write(__file__, 'getEpc: get not allow epc start str:' + newTag.epcString)
                        if self.ShowfilteredtagsEnable:
                            self.showNotAllowEpc(newTag)
                        continue  # 如果没有找到合适的开头，跳过当前数据后续操作
            except Exception as e:
                print(e)
            gtyLog.log.write(__file__, 'getEpc:' + newTag.epcString)
            # 按允许字节长度过滤
            if str(newTag.epcByteNum) not in self.state.allowEpcByteNumList:
                gtyLog.log.write(__file__,
                                 'getEpc: epcByteNum not in allowEpcByteNumList :' + str(newTag.epcString))
                if self.ShowfilteredtagsEnable:
                    self.showNotAllowEpc(newTag)
                return
            # 按gateTime过滤重复标签
            try:
                tagHasKey = newTag.epcString in self.tagsGot.checkedTagDict
                timeGapOk = tagHasKey and (abs(newTag.timeStamp - self.tagsGot.checkedTagDict[
                    newTag.epcString].timeStamp) >= self.state.gateTime)
                if (not tagHasKey) or timeGapOk:
                    self.tagsGot.totalCheckedNum += 1
                    self.tagsGot.checkedTagDict[newTag.epcString] = newTag
                    newTag.buildTimeString()
                    # 显示缓冲区增加文本，a400设备同时显示标签电量
                    if self.var.hardwareType == 'A400':
                        # 定制处理，如果是a400读取到1affffff标签（按下开关后，会写入一个模拟的1affffff标签），则修改枪响时间，不在显示缓冲区增加文本
                        if '1affffff' not in newTag.epcString:
                            self.var.epcDisplayBufText += newTag.hardwareTimeString + ":" + newTag.epcString + "," + str(
                                newTag.bat) + "V" + '\n'
                        else:
                            self.state.gunStartTime = gtyTools.gtyTypes.timeInMs(
                                newTag.hardwareTime.year, newTag.hardwareTime.month, newTag.hardwareTime.day,
                                newTag.hardwareTime.hour, newTag.hardwareTime.minute, newTag.hardwareTime.second,
                                newTag.hardwareTime.ms)
                            self.state.gunStartTimeString = tools.getTimeStamp(self.state.gunStartTime.year,
                                                                               self.state.gunStartTime.month,
                                                                               self.state.gunStartTime.day,
                                                                               self.state.gunStartTime.hour,
                                                                               self.state.gunStartTime.minute,
                                                                               self.state.gunStartTime.second, 0)
                            self.label_16.setText(newTag.hardwareTimeString)
                            font = QFont()
                            font.setPointSize(13)
                            self.label_16.setFont(font)
                            self.sendEvent('UART', "uart_beep", 0.5)
                    else:
                        self.var.epcDisplayBufText += newTag.hardwareTimeString + ":" + newTag.epcString + '\n'
                    self.var.epcDisplayBufTextLineNum += 1
                    self.tagsGot.differentCheckedNum = len(self.tagsGot.checkedTagDict)
                    tags = [newTag]
                    # 把数据发送给IO和SOCKET
                    self.sendEvent('IO', 'io_addTags', tags)
                    self.socketSendTagInfo(newTag)
                    # 把数据发送给SOCKET服务器
                    if self.var.enableSocketToServer > 0:
                        self.sendEvent('SOCKET_SERVER', 'add_tag', tags)
                    # 刷新统计量
                    ch = newTag.channelId
                    self.channels.allChs[ch - 1].tagReadNum += 1
                    # 蜂鸣器
            except Exception as e:
                print(e)
        if len(data) > 0:
            if self.var.hardwareType == 'A400':
                if self.var.beepEnable == 1:
                    self.sendEvent('UART', 'uart_beep', 0.1)

    # 处理当前是否能上网的结果
    def updateInternetConnectionState(self, state):
        self.state.internetConnectionState = state
        if self.state.internetConnectionState == 'disconnected':
            self.label_14.setText(language.mainPage_label14_disconnected)
        elif self.state.internetConnectionState == 'wwwConnected':
            self.label_14.setText(language.mainPage_label14_connectedWithoutServer)
        else:
            self.label_14.setText(language.mainPage_label14_connected)

    # 刷新Ds3231的日期
    def updateDs3231Date(self, dateList):
        if dateList[0] < 2000:
            dateList[0] += 2000
        self.hardwareTime.year = dateList[0]
        self.hardwareTime.month = dateList[1]
        self.hardwareTime.day = dateList[2]

    def checkServerConnection(self):
        timeStamp = tools.getTimeStamp(self.hardwareTime.year, self.hardwareTime.month, self.hardwareTime.day,
                                       self.hardwareTime.hour, self.hardwareTime.minute, self.hardwareTime.second, 0)
        dataList = {
            "machineId": self.state.machineId,
            "batteryPercent": self.state.batteryPercentage,
            "totalEpcRead": self.tagsGot.totalCheckedNum,
            "differentEpcRead": self.tagsGot.differentCheckedNum,
            "reader1Working": self.state.readerState1,
            "reader2Working": self.state.readerState2,
            "hardwareTime": timeStamp,
            "eventId": self.state.eventId,
            "softwareBranch": self.var.gitBranch,
            "softwareCommitId": self.var.gitCommitId,
            "firmwareVersion": self.var.compileVersion
        }
        self.sendEvent("IO", "io_checkServerConnection", [dataList])

    def updateNoticeLabel(self):
        text = ""
        for k, v in self.state.noticeLabelDict.items():
            text = text + v + ","
        text = text[:len(text) - 1]
        self.labelNotice.setText(text)

    def chBtnClicked(self, ch):
        # 按一下就不再显示通道序号
        if self.channels.displayChannelNames:
            self.channels.displayChannelNames = False
            for i in range(0, 16):
                self.channels.allChs[i].chBtn.setText(str(self.channels.allChs[i].tagReadNum))

        if self.linuxTime.secondCounter > self.channels.testNumDisplayTilSecond:
            self.channels.allChs[ch - 1].chBtn.setText(str(self.channels.allChs[ch - 1].tagReadNum))
        try:
            # 开启或关闭这个通道；
            if self.channels.allChs[ch - 1].open == 0:
                self.channels.allChs[ch - 1].open = 1
            else:
                self.channels.allChs[ch - 1].open = 0
            # 这里发送一条指令开启或关闭这个通道
            channelState = []
            for i in range(0, 16):
                channelState.append(self.channels.allChs[i].open)
            self.sendEvent('UART', 'uart_channelOpen', channelState)  # 参数是一个列表
        except Exception as e:
            print(e)

    def chEnableResponse(self, data):
        # 通道使能命令执行后的答复
        # 使按钮背景色变化，并显示或不显示读取数量；
        if self.var.hardwareType == 'F2000':
            if len(data) == 3:  # 未接地垫下位机传来只有读卡器1和2的通道情况
                data = data + [0, 0]
            ChDataList = [data[1] % 2, (data[1]) // 2 % 2, (data[1]) // 4 % 2, (data[1]) // 8 % 2, data[2] % 2,
                          (data[2]) // 2 % 2, (data[2]) // 4 % 2, (data[2]) // 8 % 2, data[3] % 2,
                          (data[3]) // 2 % 2, (data[3]) // 4 % 2, (data[3]) // 8 % 2, data[4] % 2,
                          (data[4]) // 2 % 2, (data[4]) // 4 % 2, (data[4]) // 8 % 2]
            # 用于检测天线是否连接，连接就换个颜色
            # chStateList = [data[5] % 2, (data[5]) // 2 % 2, (data[5]) // 4 % 2, (data[5]) // 8 % 2, data[6] % 2,
            #               (data[6]) // 2 % 2, (data[6]) // 4 % 2, (data[6]) // 8 % 2, data[7] % 2,
            #               (data[7]) // 2 % 2, (data[7]) // 4 % 2, (data[7]) // 8 % 2, data[8] % 2,
            #               (data[8]) // 2 % 2, (data[8]) // 4 % 2, (data[8]) // 8 % 2]
            for i in range(0, 16):
                if ChDataList[i] == 1:
                    self.channels.allChs[i].chBtn.setStyleSheet(systemConfig.param.btnHighLightStyle)
                    if self.linuxTime.secondCounter > self.channels.testNumDisplayTilSecond:
                        self.channels.allChs[i].chBtn.setText(str(self.channels.allChs[i].tagReadNum))
                    self.channels.allChs[i].open = 1
                elif ChDataList[i] == 0:
                    self.channels.allChs[i].chBtn.setStyleSheet(systemConfig.param.btnDisabledStyle)
                    self.channels.allChs[i].chBtn.setText('CH' + str(i + 1))
                    self.channels.allChs[i].open = 0
                # elif chStateList[i] == 1 and ChDataList[i] == 1:
                #     self.channels.allChs[i].chBtn.setStyleSheet(systemConfig.param.btnConnetAntenna)
                #     if self.linuxTime.secondCounter > self.channels.testNumDisplayTilSecond:
                #         self.channels.allChs[i].chBtn.setText(str(self.channels.allChs[i].tagReadNum))
                #     self.channels.allChs[i].open = 1
                # elif chStateList[i] == 1 and ChDataList[i] == 0:
                #     self.channels.allChs[i].chBtn.setStyleSheet(systemConfig.param.btnDisabledStyle)
                #     self.channels.allChs[i].chBtn.setText('CH' + str(i + 1))
                #     self.channels.allChs[i].open = 0
        elif self.var.hardwareType == 'F800' or self.var.hardwareType == 'T400':
            ChDataList = [data[1] % 2, (data[1]) // 2 % 2, (data[1]) // 4 % 2, (data[1]) // 8 % 2, data[2] % 2,
                          (data[2]) // 2 % 2, (data[2]) // 4 % 2, (data[2]) // 8 % 2]
            # 用于检测天线是否连接，连接就换个颜色
            chStateList = [data[3] % 2, (data[3]) // 2 % 2, (data[3]) // 4 % 2, (data[3]) // 8 % 2, data[4] % 2,
                           (data[4]) // 2 % 2, (data[4]) // 4 % 2, (data[4]) // 8 % 2]
            for i in range(0, 8):
                if ChDataList[i] == 1 and chStateList[i] == 0:
                    self.channels.allChs[i].chBtn.setStyleSheet(systemConfig.param.btnHighLightStyle)
                    if self.linuxTime.secondCounter > self.channels.testNumDisplayTilSecond:
                        self.channels.allChs[i].chBtn.setText(str(self.channels.allChs[i].tagReadNum))
                    self.channels.allChs[i].open = 1
                elif ChDataList[i] == 0 and chStateList[i] == 0:
                    self.channels.allChs[i].chBtn.setStyleSheet(systemConfig.param.btnDisabledStyle)
                    self.channels.allChs[i].chBtn.setText('CH' + str(i + 1))
                    self.channels.allChs[i].open = 0
                elif chStateList[i] == 1 and ChDataList[i] == 1:
                    self.channels.allChs[i].chBtn.setStyleSheet(systemConfig.param.btnConnetAntenna)
                    if self.linuxTime.secondCounter > self.channels.testNumDisplayTilSecond:
                        self.channels.allChs[i].chBtn.setText(str(self.channels.allChs[i].tagReadNum))
                    self.channels.allChs[i].open = 1
                elif chStateList[i] == 1 and ChDataList[i] == 0:
                    self.channels.allChs[i].chBtn.setStyleSheet(systemConfig.param.btnDisabledStyle)
                    self.channels.allChs[i].chBtn.setText('CH' + str(i + 1))
                    self.channels.allChs[i].open = 0

    def updateTestTagShow(self, data):
        print(__file__, "test card get")
        for i in range(0, 16):
            if data[i] > 0:
                self.channels.allChs[i].testTagReadNum += data[i]
                self.channels.allChs[i].chBtn.setText('T:' + str(self.channels.allChs[i].testTagReadNum))
                self.channels.testNumDisplayTilSecond = self.linuxTime.secondCounter + 10

    def stm32Cmd(self, cmd):
        if self.configHandlers.state.read('machine', 'release') != 'release':
            if cmd[0] == 'shut down':
                self.powerManage('powerOff')
            if cmd[0] == 'reboot':
                self.powerManage('reboot')

    # 刷新页面待上传数据
    def updateCpValueNumLeft(self, info):
        self.label_30.setText(info)

    # 显示警告信息
    def showWarning(self, warningInfo):
        s = '\r\n**' + language.mainPage_warning + '**: ' + warningInfo
        s += '\r\n'
        self.textBrowser.append(s)

    # 提示软件需要升级
    def softwareUpdateNotice(self, data):
        print(__file__, 'softwareUpdateNotice:', data)
        if data[0] == 'software':
            self.state.updateNotice = 'software'
        if data[0] == 'firmware':
            self.state.updateNotice = 'firmware'

    # 更新上传结果文件是否成功
    def handleFileUploadResult(self, res):
        dis = time.strftime('%H:%M:%S ', time.localtime(time.time()))
        if res[0] == 'successful':
            self.outputLog(dis + language.mainPage_dataFileUploadSuccessful + " " + res[1])
        else:
            self.outputLog(dis + language.mainPage_dataFileUploadFailed + " " + res[1])

    def updateFirmwareVersion(self, data):
        if self.var.getFirmwareFlag == 1:
            return
        self.var.getFirmwareFlag = 1
        # 获得编译版本
        if len(data) >= 4:
            self.var.compileVersion = data[2] * 250 + data[3]
            self.labelGitVersion.setText(self.labelGitVersion.text() + " / " + str(self.var.compileVersion))
        print(__file__, 'firmware ', data)
        # 判断是否满足最低固件要求
        firmwareString = str(data[0]) + '.' + str(data[1]) + '.' + str(self.var.compileVersion)
        lowest = float(systemConfig.lowestFirmware)
        now = float(str(data[0]) + '.' + str(data[1]))
        if now < lowest:
            s = '<'
        elif now == lowest:
            s = '='
        else:
            s = '>'
        self.log('firmware: ' + firmwareString + s + systemConfig.lowestFirmware + " required lowest.")
        if s == '<':
            self.log('Firmware version is too low to work correctly, please update! ')
        self.configHandlers.state.write('machine', 'firmwareversion',
                                        str(data[0]) + '.' + str(data[1]) + '.' + str(self.var.compileVersion))
        self.updateValuesFromEventConfigFile()

    '''
        响应socket
    '''

    def socketSendHeartBeat(self):
        self.sendEvent('SOCKET', 'socket_send', ['heartBeat', ""])
        sendString = "batteryPercent=" + str(self.state.batteryPercentage) + \
                     ",totalTagsRead=" + str(self.tagsGot.totalCheckedNum) + \
                     ",differentTagsRead=" + str(self.tagsGot.differentCheckedNum) + \
                     ",reader1Working=" + str(self.state.readerState1) + \
                     ",reader2Working=" + str(self.state.readerState2) + \
                     ",eventId=" + str(self.state.eventId)
        self.sendEvent('SOCKET', 'socket_send', ['machineState', sendString])

    def socketSendTagInfo(self, tag):
        if self.var.hardwareType == 'A400':
            self.sendEvent('SOCKET', 'socket_send', ['epc',
                                                     tag.hardwareDateString + "_" + tag.hardwareTimeString + ',' + tag.epcString + ',' + tag.bat + 'V'])
        else:
            if self.formatNum in ['format2', 'format8']:
                readerID = str((tag.channelId - 1) // 4 + 1)
                self.sendEvent('SOCKET', 'socket_send', ['epc',
                                                         tag.hardwareDateString + "_" + tag.hardwareTimeString + ',' + tag.epcString + ',' + readerID + ',' + str(
                                                             tag.channelId) +  ',-'+ str(tag.rssi)])
            else:
                self.sendEvent('SOCKET', 'socket_send',
                               ['epc', tag.hardwareDateString + "_" + tag.hardwareTimeString + ',' + tag.epcString])

    def socketSendDate(self):
        self.sendEvent('SOCKET', 'socket_send', ['machineDate', str(self.hardwareTime.year) + '-' +
                                                 str(self.hardwareTime.month) + '-' + str(self.hardwareTime.day)])

    def socketSendTime(self):
        self.sendEvent('SOCKET', 'socket_send', ['machineTime', '%02d' % self.hardwareTime.hour + ':%02d' %
                                                 self.hardwareTime.minute + ':%02d' % self.hardwareTime.second
                                                 + '.%03d' % self.hardwareTime.ms])

    def socketSendPackDataResult(self, flag):
        self.sendEvent('SOCKET', 'socket_send', ['packDataResult', flag])

    def socketGetGunTime(self):
        if self.state.gunStartTime is not None:
            s = "%04d-%02d-%02d_%02d:%02d:%02d.%03d" % (
                self.state.gunStartTime.year,
                self.state.gunStartTime.month,
                self.state.gunStartTime.day,
                self.state.gunStartTime.hour,
                self.state.gunStartTime.minute,
                self.state.gunStartTime.second,
                self.state.gunStartTime.ms
            )
            socketCmdList = ['gunTime', s]
        else:
            socketCmdList = ['gunTime', 'gunNotStarted']
        self.sendEvent('SOCKET', 'socket_send', socketCmdList)

    def getRunInfo(self):
        self.sendEvent('UI', 'ui_cpuRamInfo', systemTools.getRunInfo())

    def updateCpuRamInfo(self, info):
        if info[0] < 10:
            s1 = 'cpu:   ' + str(info[0]) + '%'
        else:
            s1 = 'cpu: ' + str(info[0]) + '%'
        s2 = 'ram: ' + str(info[1]) + '%'
        s3 = 'ps: ' + str(info[2])
        s4 = 'thr: ' + str(info[3])
        s5 = 'temp: ' + str(info[4]) + '°C'
        self.labelStatus.setText(s1 + ', ' + s2 + ', ' + s3 + ', ' + s4 + ', ' + s5)
        if info[0] > 70 or info[1] > 70:
            self.labelStatus.setStyleSheet("color:rgb(200,0,0)")
        else:
            self.labelStatus.setStyleSheet("color:rgb(0,200,0)")
        # 记录高cpu的情况
        gtyLog.log.write(__file__, s1, s2, s3, s4, self.linuxTime.secondCounter)

    def getGitNewVersion(self, data):
        self.var.remoteGitDevVersion = data[0]
        self.var.remoteGitMasterVersion = data[1]
        print(__file__, 'getGitNewVersion', data)
        gtyLog.log.write(__file__, 'remote git version', data)
        self.log('')
        self.log('remote master version: ' + self.var.remoteGitMasterVersion)
        self.log('remote dev version: ' + self.var.remoteGitDevVersion)
        self.log('')
        if self.var.gitBranch.upper() == 'MASTER':
            if self.var.gitCommitId != self.var.remoteGitMasterVersion:
                self.log(language.mainPage_newSoftwareWarning)

    def toggleChLog(self):
        # if self.var.hardwareType == "F800":
        #     return
        if self.state.displayChannels:
            # 隐藏通道
            self.channels.hide(True, target='active')
            self.state.displayChannels = False
            self.textBrowser.show()
            self.changeDisplayButton.setText(language.mainPage_displayChannels)
            if self.var.hardwareType == 'F2000':
                self.channels.hide(True, target='pro')
                self.channels.hide(True, target='innerChannels')
                self.Passive_Button.hide()
                self.passiveRBtn.hide()
                self.activeRBtn.hide()
            if self.var.hardwareType == 'F800' or self.var.hardwareType == 'T400':
                self.channels.hide(True, target='active')
                self.Passive_Button.hide()
                self.stopReadingButton.hide()
                self.startReadingButton.hide()
        else:
            # 显示通道
            self.channels.hide(False, target='active')
            self.state.displayChannels = True
            self.textBrowser.hide()
            self.changeDisplayButton.setText(language.mainPage_displayLog)
            if self.var.hardwareType == 'F2000':
                self.channels.hide(False, target='pro')
                self.channels.hide(False, target='innerChannels')
                self.Passive_Button.show()
                self.passiveRBtn.show()
                self.activeRBtn.show()
            if self.var.hardwareType == 'F800' or self.var.hardwareType == 'T400':
                self.channels.hide(True, target='active')
                self.Passive_Button.show()
                self.stopReadingButton.show()
                self.startReadingButton.show()

    # 更新读卡器功率数值，用来判定读卡器是否已经正确配置
    def getReaderPower(self, d):
        readerId = int(d[0])
        power = int(d[1])
        print(__file__, 'getReaderPower', readerId, power)
        if readerId == 1:
            self.var.reader1Power = power
        if readerId == 2:
            self.var.reader2Power = power
        if readerId == 3:
            self.var.reader3Power = power
        if readerId == 4:
            self.var.reader4Power = power

    # 用服务器设置年月日，只当服务器时间和本地时间相差5秒以内时，才设置
    def setDateTimeFromWeb(self, d):
        # 只设置5次
        if self.var.setDateTimeFromWebTimes <= 6:
            datetimeString = d[0]
            try:
                t1 = datetime.datetime.strptime(datetimeString, '%Y-%m-%d_%H:%M:%S')
                hardwareTimeString = f"{self.hardwareTime.year}-{self.hardwareTime.month:02d}-{self.hardwareTime.day:02d}_{self.hardwareTime.hour:02d}:{self.hardwareTime.minute:02d}:{self.hardwareTime.second:02d} "
                t2 = datetime.datetime.strptime(hardwareTimeString, '%Y-%m-%d_%H:%M:%S')
                diff = t1 - t2
                if diff.total_seconds() > 5:
                    dateTimeParts = str(datetimeString).replace('-', ':').replace('_', ":").split(":")
                    # 偶数秒设定时间
                    if self.var.setDateTimeFromWebTimes % 2 == 0:
                        self.sendEvent("UART", "uart_setDs3231Time",
                                       [int(dateTimeParts[3]), int(dateTimeParts[4]), int(dateTimeParts[5])])
                        print(__file__, ["uart_setDs3231Time",
                                         [int(dateTimeParts[3]), int(dateTimeParts[4]), int(dateTimeParts[5])]])
                    # 奇数秒设定日期
                    if self.var.setDateTimeFromWebTimes % 2 == 1:
                        self.sendEvent("UART", "uart_setDs3231Date",
                                       [int(dateTimeParts[0]) - 2000, int(dateTimeParts[1]), int(dateTimeParts[2])])
                        print(__file__, ["uart_setDs3231Date",
                                         [int(dateTimeParts[0]), int(dateTimeParts[1]), int(dateTimeParts[2])]])
                    self.var.setDateTimeFromWebTimes += 1
            except Exception as e:
                print(e)

    # 有源系统
    def activeSetting(self):
        e = activeSetting.ActiveSetting(self, self.eventQ)
        if e.exec_():
            pass

    def operate(self):
        e = operate.Operate(self, self.eventQ)
        if e.exec_():
            pass

    # 收到了有源读卡器的心跳包
    def getActiveHeartBeat(self, data):
        loop1 = '---'
        loop2 = '---'
        power = '---'
        channel = '---'
        states = ['Off', 'On', 'Break']
        try:
            loop1 = states[data[0]]
            loop2 = states[data[1]]
            power = str(data[4]) + '%'
            self.var.activeReaderPower = power # 记录有源读卡器的功率
            channel = str(data[5])
            if loop1 == 'break':
                loop1 = "<font color=\"red\">break</font>"
            if loop2 == 'break':
                loop2 = "<font color=\"red\">break</font>"
        except Exception as e:
            print(e)
        stateString = 'L1:' + loop1 + ", L2:" + loop2 + ', power:' + power + ', ch:' + channel
        self.label_34.setText(stateString)
        # 断线检测
        if 'break'.upper() in loop1.lower() or 'break'.upper() in loop2.lower():
            self.sendEvent('UART', 'uart_beep', 0.5)
        # 通过socket发送有源心跳包
        dataStr = "loop1" + loop1 + ",loop2" + loop2 + ",channel" + channel + ",power" + power
        self.sendEvent("SOCKET", "socket_send", ['activeSystemState', dataStr])

    # 启动时使能或禁用蜂鸣器
    def toggleBeep(self):
        if self.configHandlers.machine.read('machine', 'beepEnable') == '0':
            self.var.beepEnable = 0
            self.sendEvent('UART', 'uart_beepEnable', [0])
        else:
            self.configHandlers.machine.write('machine', 'beepEnable', '1')
            self.var.beepEnable = 1
            self.sendEvent('UART', 'uart_beepEnable', [1])

    def setPassiveAction(self):
        self.sendEvent('UART', 'uart_setPassive')
        self.configHandlers.machine.write('machine', 'machineState', 'Passive')
        self.Passive_Button.setDisabled(False)
        self.Active_Button.setDisabled(True)
        self.Active_Button.setStyleSheet(systemConfig.param.btnDisabledStyle)
        self.Passive_Button.setStyleSheet(systemConfig.param.btnEnabledStyle)
        self.passiveRBtn.setChecked(True)

    def setActiveAction(self):
        self.sendEvent('UART', 'uart_setActive')
        self.configHandlers.machine.write('machine', 'machineState', 'Active')
        self.Active_Button.setDisabled(False)
        self.Passive_Button.setDisabled(True)
        self.Passive_Button.setStyleSheet(systemConfig.param.btnDisabledStyle)
        self.Active_Button.setStyleSheet(systemConfig.param.btnEnabledStyle)
        self.activeRBtn.setChecked(True)

    # 启动时设置无源或是有源
    def setPassvieOrActive(self):
        if self.configHandlers.machine.read('machine', 'machineState') == 'Active':
            self.setActiveAction()
            self.sendEvent('UI', 'ui_setPassOrAct', 'Active')
        else:
            self.setPassiveAction()
            self.sendEvent('UI', 'ui_setPassOrAct', 'Passive')

    def setPassiveOrActiveSlog(self, string):
        if string == '有源' or string == 'Active':
            self.setActiveAction()
        elif string == '无源' or string == 'Passive':
            self.setPassiveAction()

    def askDialogSetText(self, string):
        self.setWindowTitle('Check')
        self.dialog.pushButton.setText(language.mainPage_OK)
        self.dialog.pushButton2.setText(language.mainPage_cancel)
        if string == 'Active':
            self.dialog.label.setText(language.mainPage_setActive)
        elif string == 'Passive':
            self.dialog.label.setText(language.mainPage_setPassive)

    def setPassive(self):
        self.askDialogSetText('Passive')
        if self.dialog.exec_() == QDialog.Accepted:
            self.setPassiveAction()
        else:
            # 先判断当前是不是无源，如果不是就固定radiobtn
            if self.configHandlers.machine.read('machine', 'machineState') == 'Passive':
                pass
            else:
                self.passiveRBtn.setChecked(False)
                self.activeRBtn.setChecked(True)

    def setActive(self):
        self.askDialogSetText('Active')
        if self.dialog.exec_() == QDialog.Accepted:
            self.setActiveAction()
        else:
            if self.configHandlers.machine.read('machine', 'machineState') == 'Active':
                pass
            else:
                self.passiveRBtn.setChecked(True)
                self.activeRBtn.setChecked(False)

    def startReading(self):
        self.sendEvent('UI', 'ui_startOrStropReading', ["1", "on"])
        self.sendEvent('UI', 'ui_startOrStropReading', ["2", "on"])

    def stopReading(self):
        self.sendEvent('UI', 'ui_startOrStropReading', ["1", "off"])
        self.sendEvent('UI', 'ui_startOrStropReading', ["2", "off"])

    def update_shutdown_time(self):
        """
        更新倒计时，并在倒计时结束时执行关机操作
        """
        self.dialog.label.setText("will shutdown after ")
        self.dialog.label_2.setText(str(self.shutDownTime) + "s")  # 确保显示为字符串
        self.shutDownTime -= 1

        if self.shutDownTime < 0:  # 倒计时结束
            self.timer_shutdown.stop()  # 停止计时器
            self.execute_shutdown()  # 执行关机逻辑

    def execute_shutdown(self):
        """
        执行关机操作
        """
        self.sendEvent('UART', 'uart_shutDown', [])
        gtyLog.log.write(__file__, 'Shoutdown by user button')
        gtyTools.tools.linuxSudoCmd('halt')  # 关机命令
        gtyTools.tools.linuxSudoCmd('killall python3')  # 停止所有 Python3 进程

    def showShutdown(self):
        """
        显示关机对话框
        """
        gtyLog.log.write(__file__, 'Shutdown page opened by long press button')
        self.dialog.pushButton.setText("Shutdown")
        self.dialog.pushButton2.setText("Cancel")
        self.dialog.label.setStyleSheet("font-size: 18px;")
        self.dialog.label_2.setStyleSheet("font-size: 16px; color: red;")
        self.dialog.pushButton.setStyleSheet("font-size: 14px;")
        self.dialog.pushButton2.setStyleSheet("font-size: 14px;")
        self.shutDownTime = 60  # 重置倒计时时间
        self.timer_shutdown = QTimer()  # 创建定时器
        self.timer_shutdown.timeout.connect(self.update_shutdown_time)
        # 启动计时器
        self.timer_shutdown.start(1000)  # 每秒触发一次更新函数

        # 打开对话框并等待用户操作
        if self.dialog.exec_() == QDialog.Accepted:
            self.timer_shutdown.stop()  # 如果用户确认，停止计时器
            self.execute_shutdown()  # 执行关机操作
        else:
            self.timer_shutdown.stop()  # 如果用户取消，停止计时器
            gtyLog.log.write(__file__, 'Shutdown canceled by user')

    def setGateTime(self, gateTime):
        try:
            self.configHandlers.machine.write("machine", "gateTime", gateTime, "float")
            gtyLog.log.write(__file__, 'UI set Gate time set to ' + str(gateTime))
            self.state.gateTime = self.configHandlers.machine.read("machine", "gateTime", "float", 1)
        except Exception as e:
            gtyLog.log.write(__file__, 'UI set Gate time failed with error ' + str(e))

    def showNotAllowEpc(self, tag):
        tag.buildTimeString()
        self.outputLog(tag.hardwareTimeString + ":" + 'not allowed EPC ' + tag.epcString + '\n', 1, 'yellow')

    def socketGetReaderPower(self, readerID):
        if self.configHandlers.machine.read('machine', 'machineState') == 'Active':
            readerPower = str(self.var.activeReaderPower)
        else:
            if self.var.hardwareType == 'F2000':
                readerPower = f'{self.var.reader1Power},{self.var.reader2Power},{self.var.reader3Power},{self.var.reader4Power}'
            elif self.var.hardwareType == 'F800':
                readerPower = f'{self.var.reader1Power},{self.var.reader2Power}'
            else:
                readerPower = str(self.var.activeReaderPower)

        self.sendEvent('SOCKET', 'socket_send', ['readerPower', readerPower])

    def updateReaderPower(self,data):
        readerID = int(data[0])
        power = int(data[1])
        if readerID == 1:
            self.var.reader1Power = power
        if readerID == 2:
            self.var.reader2Power = power
        if readerID == 3:
            self.var.reader3Power = power
        if readerID == 4:
            self.var.reader4Power = power

    def socketGetReaderChannel(self):
        readerChannel = ""
        if self.configHandlers.machine.read('machine', 'machineState') == 'Active':
            pass
        elif self.var.hardwareType == 'F2000':
            readerChannel = ''
            for i in range(0, 16):
                if self.channels.allChs[i].open ==1:
                    readerChannel += '1'
                else:
                    readerChannel += '0'
        elif self.var.hardwareType == 'F800':
            readerChannel = ''
            for i in range(0, 8):
                if self.channels.allChs[i].open ==1:
                    readerChannel += '1'
                else:
                    readerChannel += '0'
        else:
            readerChannel = "None"
        self.sendEvent('SOCKET', 'socket_send', ['readerChannel', readerChannel])

    def update_start_stop_reading_btn(self):
        reader_states = {
            'F2000': [self.state.readerState1, self.state.readerState2,
                      self.state.readerState3, self.state.readerState4],
            'F800': [self.state.readerState1, self.state.readerState2]
        }
        states = reader_states.get(self.var.hardwareType, [])
        if states.count('reading') == 0:
            self.startReadingButton.setStyleSheet(systemConfig.param.btnEnabledStyle)
        else:
            self.startReadingButton.setStyleSheet(systemConfig.param.btnConnetAntenna)

    def updateReaderStatus(self, data):
        self.state.readerState1 = 'reading' if data[0] == 1 else 'stopped'
        self.label_8.setText(language.mainPage_reading) if data[0] == 1 else self.label_8.setText(language.mainPage_stopReading)
        self.state.readerState2 = 'reading' if data[1] == 1 else 'stopped'
        self.label_28.setText(language.mainPage_reading) if data[1] == 1 else self.label_10.setText(language.mainPage_stopReading)
        if self.var.hardwareType == 'F2000':
            self.state.readerState3 = 'reading' if data[2] == 1 else 'stopped'
            self.state.readerState4 = 'reading' if data[3] == 1 else 'stopped'
        self.update_start_stop_reading_btn()

def main(eventQ):
    print("===================UI task started===================")
    try:
        gtyLog.log.write(__file__, 'ui process starting ...')
        app = QApplication(sys.argv)
        ex = MainGuiModel(eventQ)
        ex.show()
        app.exec_()
        gtyLog.log.write(__file__, 'ui process ended...')
        sys.exit()
    except Exception as e:
        print(__file__, e, traceback.extract_stack())
        gtyLog.log.write(__file__, e, traceback.extract_stack())
